package lambdasinaction.chap8.my;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

/**
 * 工厂模式 使用工厂模式，你无需向客户暴露实例化的逻辑就能完成对象的创建。 比如，我们假定你为一家银行工作，他们需要一种方式创建不同的金融产品： 贷款、期权、股票，等等
 * 通常，你会创建一个工厂类，它包含一个负责实现不同对象的方法，如下所示：
 *
 * @author Fish
 * @since 0.0.1 2018/8/9 11:11
 */
public class MyFactoryMain {

  /**
   * 创建一个 Map，将产品名映射到对应的构造函数：
   */
  private final static Map<String, Supplier<Product>> map = new HashMap<>();

  static {
    map.put("loan", Loan::new);
    map.put("stock", Stock::new);
    map.put("bond", Bond::new);
  }

  public static void main(String[] args) {
    Product p1 = ProductFactory.createProduct("loan");

    Supplier<Product> loanSupplier = Loan::new;
    Product p2 = loanSupplier.get();

    Product p3 = ProductFactory.createProductLambda("loan");
  }

  /**
   * 产品
   */
  private interface Product {

  }

  static private class ProductFactory {

    /**
     * createProduct 方法可以通过附加的逻辑来设置每个创建的产品
     * 但是带来的好处也显而易见，你在创建对象时不用再担心会将构造函数或者配置暴露给客户
     * 这使得客户创建产品时更加简单
     * @param name
     * @return
     */
    public static Product createProduct(String name) {
      switch (name) {
        case "loan":
          return new Loan();
        case "stock":
          return new Stock();
        case "bond":
          return new Bond();
        default:
          throw new RuntimeException("No such product " + name);
      }
    }

    /**
     * 使用 Lambda 表达式
     * 第3章中，我们已经知道可以像引用方法一样引用构造函数。
     * 比如，下面就是一个引用贷款（Loan）构造函数的示例：
     * 现在，你可以像之前使用工厂设计模式那样，利用这个 Map 来实例化不同的产品
     * 这是个全新的尝试，它使用 Java8中的新特性达到了传统工厂模式同样的效果。
     * 但是，如果工厂方法 createProduct 需要接收多个传递给产品构造方法的参数，
     * 这种方式的扩展性不是很好。
     * 你不得不提供不同的函数接口，无法采用之前统一使用一个简单接口的方式。
     * @param name
     * @return
     */
    public static Product createProductLambda(String name) {
      Supplier<Product> p = map.get(name);
      if (p != null) {
        return p.get();
      }
      throw new RuntimeException("No such product_lambda " + name);
    }
  }

  /**
   * 贷款
   */
  static private class Loan implements Product {

  }

  /**
   * 股票
   */
  static private class Stock implements Product {

  }

  /**
   * 债务
   */
  static private class Bond implements Product {

  }
}
